import os
import shutil
from PyInstaller.__main__ import run as run_pyinstaller

def build():
    """
    函数说明：使用 PyInstaller 将 FastAPI 应用程序打包成单个可执行文件。

    行为：
    - 清理旧的构建目录和文件。
    - 定义 PyInstaller 的参数，包括：
        - 单文件模式 (`--onefile`)。
        - 指定应用程序入口点 (`app/main.py`)。
        - 添加数据文件（`frontend` 目录）。
        - 为可执行文件命名 (`barcode_scanner`)。
        - 添加图标（如果 `icon.ico` 存在）。
        - 显示控制台窗口（移除 `--windowed`）。
        - 优化级别设为 1，保留 docstring 以兼容依赖（PLY/pycparser）。
    - 运行 PyInstaller。
    - 清理临时构建文件。
    """
    # 清理旧的构建产物
    for p in ("dist", "build"):
        if os.path.exists(p):
            try:
                shutil.rmtree(p)
            except PermissionError:
                print(f"警告: 无法删除 {p}（可能被占用），将跳过清理。")
            except Exception as e:
                print(f"警告: 清理 {p} 失败：{e}")
    if os.path.exists("barcode_scanner.spec"):
        try:
            os.remove("barcode_scanner.spec")
        except Exception as e:
            print(f"警告: 删除 spec 失败：{e}")

    # PyInstaller 参数
    opts = [
        'app/main.py',
        '--name=barcode_scanner',
        '--onefile',
        '--windowed',
        '--add-data=frontend;frontend',
        # 精简体积：无需把源码 app 目录作为数据打包
        '--hidden-import=fastapi',
        '--hidden-import=uvicorn',
        '--hidden-import=pyzbar',
        '--hidden-import=cv2',
        '--hidden-import=httpx',
        '--hidden-import=anyio',
        '--hidden-import=zxing',
        '--hidden-import=webview',
        '--hidden-import=pywebview',
        # 剪贴板相关的 pywin32 模块
        '--hidden-import=win32clipboard',
        '--hidden-import=win32con',
        # 解析器与语法工具（PLY/pycparser）
        '--hidden-import=ply',
        '--hidden-import=pycparser',
        '--collect-all=ply',
        '--collect-all=pycparser',
        '--collect-binaries=pyzbar',
        '--collect-data=pyzbar',
        '--collect-all=pyzbar',
        '--collect-all=webview',
        # 体积优化（保持docstring避免PLY规则被strip）
        '--exclude-module=pytest',
        '--clean',
        '--noconfirm',
        '--optimize=1',
    ]

    # 添加图标（如果存在）
    if os.path.exists('icon.ico'):
        opts.append('--icon=icon.ico')

    print("Running PyInstaller with options:")
    print(opts)

    # 运行 PyInstaller
    run_pyinstaller(opts)

    # 清理临时文件
    if os.path.exists("build"):
        try:
            shutil.rmtree("build")
        except Exception:
            pass
    if os.path.exists("barcode_scanner.spec"):
        try:
            os.remove("barcode_scanner.spec")
        except Exception:
            pass

if __name__ == '__main__':
    build()